﻿namespace EFMLEditor
{
    using System;
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Drawing;
    using System.IO;
    using System.Linq;
    using System.Windows.Forms;

    using Creek.Extensibility.Plugins;
    using Creek.UI.Metro.Forms;
    using Creek.UI.Tabstrip.Control;

    using Crom.Controls.Docking;

    using EFMLEditor.DockingForms;
    using EFMLEditor.Internal;
    using EFMLEditor.Internal.Controls.Components;
    using EFMLEditor.Internal.Dialogs;
    using EFMLEditor.Pages;

    using EFML_Runtime;

    using Editor;
    using Editor.Contracts;

    [PlugInApplication("Editor")]
    public partial class Form1 : MetroForm, IEditorApplication
    {
        #region Constructors and Destructors

        private EditorPlugInManager _plugInManager;

        public ErrorList errorLister1;

        public Edit tabControl1;

        public Explorer explorer;

        public Form1()
        {
            this.InitializeComponent();
        }

        private Form FormsFactory(Guid identifier)
        {
            var g = identifier.ToString();
            switch (g)
            {
                case "f3cc9efe-2b96-467a-9661-384345c1861c":
                    return this.explorer;
                case "39e0431c-88f4-41bf-9efa-9b71d8d50781":
                    return this.errorLister1;
                case "9efe2525-9bb3-487c-8955-a3e139cfe8b6":
                    return this.tabControl1;
            }
            return null;
        }

        #endregion

        private void treeView1_NodeMouseDoubleClick(object sender, TreeNodeMouseClickEventArgs e)
        {
            if (e.Node.Text == "Properties")
            {
                var pp = new PropertiesPage { Dock = DockStyle.Fill };

                this.tabControl1.faTabStrip1.AddTab(new FATabStripItem("Properties", pp), true);
            }
            else
            {
                if (e.Node.Parent.Text == "Strings")
                {
                    var doc = Application.Strings.getDocument(e.Node.Text);

                    if (doc != null)
                    {
                        if (doc.isOpened)
                        {
                            this.tabControl1.faTabStrip1.SelectItem(new FATabStripItem(doc.Name, null));
                            this.tabControl1.faTabStrip1.TabStripItemClosing += args => doc.isOpened = false;
                        }
                        else
                        {
                            var cp = new StringsPage(doc)
                                { Dock = DockStyle.Fill };
                            doc.isOpened = true;

                            this.tabControl1.faTabStrip1.AddTab(new FATabStripItem(doc.Name, cp));
                        }
                    }
                }
                else
                {
                    Document doc = Application.Documents.getDocument(e.Node.Text);

                    if (doc != null)
                    {
                        if (doc.isOpened)
                        {
                            this.tabControl1.faTabStrip1.SelectItem(new FATabStripItem(doc.Name, null));
                            this.tabControl1.faTabStrip1.TabStripItemClosing += args => doc.isOpened = false;
                        }
                        else
                        {
                            var cp = new CodePage(doc)
                                { Dock = DockStyle.Fill, fastColoredTextBox1 = { Text = doc.Value } };
                            doc.isOpened = true;

                            this.tabControl1.faTabStrip1.AddTab(new FATabStripItem(doc.Name, cp));
                        }
                    }
                }
            }
        }

        private void erstellenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var mc = new MacroContext();
            mc.AddVar("hello", "world");

            string path = Global.Get("project_path");
            string buildp = path  + @"\Build\";

            mc.AddVar("projectPath", path );
            mc.AddVar("buildPath", buildp);

            Global.Add("buildPath", buildp);

            if (Global.Get("application_version") == "")
            {
                ErrorContainer.Add("Properties", "'Version' cannot be empty");
                this.errorLister1.errorLister1.Reload();
            }
            if (Global.Get("application_description") == "")
            {
                ErrorContainer.Add("Properties", "'Description' cannot be empty");
                this.errorLister1.errorLister1.Reload();
            }
            if (Global.Get("application_copyright") == "")
            {
                ErrorContainer.Add("Properties", "'Copyright' cannot be empty");
                this.errorLister1.errorLister1.Reload();
            }
            if (Global.Get("application_icon") == "")
            {
                ErrorContainer.Add("Properties", "'Icon' cannot be empty");
                this.errorLister1.errorLister1.Reload();
            }

            if (this.errorLister1.errorLister1.ErrorsCount == 0)
            {
                Macro.Execute(Project.Get("application_präbuildevent"), mc);

                var ex = new Exeutable { Info = { ApplicationName = Global.Get("application_name") } };

                foreach (var s in Application.Strings)
                {
                    ex.Strings.Add(s.Name, s.Value);
                }

                ex.Info.Author = Global.Get("application_author");
                ex.Info.Copyright = Global.Get("application_copyright");
                ex.Info.Description = Global.Get("application_description");
                ex.Info.Version = Global.Get("application_version");
                ex.Info.Website = Global.Get("application_website");

                ex.MainForm = Global.Get("application_mainwindow");
                ex.MainLanguage = Global.Get("application_mainlanguage");

                var ms = new MemoryStream();
                new Icon(Global.Get("application_icon")).Save(ms);
                ex.Info.Icon = ms.ToArray();

                ex.Save(new FileStream(buildp + Global.Get("application_name") + ".era", FileMode.OpenOrCreate));

                Macro.Execute(Project.Get("application_postbuildevent"), mc);
            }
        }

        #region Implementation of IEditorApplication

        public Control FindControl(string name)
        {
            switch (name)
            {
                case "menu":
                    return this.menuStrip1;
                case "explorer":
                    return this.explorer;
            }
            return null;
        }

        public Form GetWindow(string name)
        {
            return this;
        }

        public ToolStripMenuItem GetMenu(string name)
        {
            switch (name)
            {
                case "file":
                    return this.dateiToolStripMenuItem;
                case "project":
                    return this.projektToolStripMenuItem1;
                case "help":
                    return this.helpToolStripMenuItem;
            }
            return null;
        }

        #endregion

        private void projektToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var np = new NewProjectDialog();
            np.ShowDialog();
            this.explorer.treeView1.Nodes.Add(Global.Get<TreeNode>("projectNode"));
            this.explorer.treeView1.Nodes[0].Expand();
            Application.isLoaded = true;

            var ds = new DockStateSerializer(
                this.dockContainer1, System.Windows.Forms.Application.StartupPath + "\\dock.xml");
            ds.Load(true, this.FormsFactory);
        }

        private void öffnenToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var openFileDialog1 = EditorFileDialog.NewOpen();
            openFileDialog1.Filter = "EFML Project File (*.proj)|*.proj";
            if (openFileDialog1.ShowDialog() == DialogResult.OK)
            {
                var pf = new ProjectFile();
                pf.Load(openFileDialog1.FileName);

                var fold = new FileInfo(openFileDialog1.FileName);
                var props = new PropsReader();
                props.Load(fold.DirectoryName + pf.PropsPath);

                Global.Add("project_path", fold.DirectoryName);

                foreach (var w in pf.Windows)
                {
                    string window = File.ReadAllText(fold.DirectoryName + "\\" + w.Key);
                    string code = File.ReadAllText(fold.DirectoryName + "\\" + w.Value);

                    var wDoc = new Document { Name = w.Key, Value = window };
                    var cDoc = new Document { Name = w.Value, Value = code };

                    Application.Documents.Add(wDoc);
                    Application.Documents.Add(cDoc);
                }
                foreach (var d in from s in pf.Strings
                                  let code = File.ReadAllText(props.Path + "\\Strings\\" + s)
                                  select new Document { Name = s, Value = code })
                {
                    Application.Strings.Add(d);
                }

                Global.Add("propsPath", fold.DirectoryName + pf.PropsPath);

                Global.Add("application_name", props["appname"]);
                Global.Add("application_icon", props["icon"]);
                Global.Add("application_author", props["author"]);
                Global.Add("application_version", props["version"]);
                Global.Add("application_copyright", props["copyright"]);
                Global.Add("application_description", props["description"]);
                Global.Add("application_website", props["website"]);

                Global.Add("application_präbuildevent", props["praebuild"]);
                Global.Add("application_postbuildevent", props["postbuild"]);

                Global.Add("application_mainlanguage", props["mainlanguage"]);
                Global.Add("application_mainwindow", props["mainwindow"]);

                Global.Add("projectfile", pf);
                Global.Add("props", props);

                Application.OnLoad(TreeProjectBuilder.Build(props["appname"], pf.Windows, pf.Strings));
                this.explorer.treeView1.Nodes[0].Expand();

                var ds = new DockStateSerializer(
                    this.dockContainer1, System.Windows.Forms.Application.StartupPath + "\\dock.xml");
                ds.Load(true, this.FormsFactory);

                Application.isLoaded = true;
                Application.isDirty = false;
            }
        }

        private void checkForUpdatesToolStripMenuItem_Click(object sender, EventArgs e)
        {
            UpdateController.CheckDialog();
        }

        private void speichernToolStripMenuItem_Click(object sender, EventArgs e)
        {
            SaveFileDialog svd = EditorFileDialog.NewSave();
            svd.Filter = "EFML Project File (*.proj)|*.proj";
            if (svd.ShowDialog() == DialogResult.OK)
            {
                var pf = Global.Get<ProjectFile>("projectfile");
                // pf.Save(svd.FileName); // Todo: Fix Saving Projectfile

                var fi = new FileInfo(svd.FileName);

                foreach (var d in Application.Documents)
                {
                    File.WriteAllText(fi.DirectoryName + d.Name, d.Value);
                }
                foreach (var s in Application.Strings)
                {
                    var p = new FileInfo(Global.Get("propsPath"));
                    File.WriteAllText(p.DirectoryName + "\\" + s.Name, s.Value);
                }

                var dic = new Dictionary<string, string>
                    {
                        { "appname", Global.Get("application_name") },
                        { "icon", Global.Get("application_icon") },
                        { "author", Global.Get("application_author") },
                        { "version", Global.Get("application_version") },
                        { "copyright", Global.Get("application_copyright") },
                        { "description", Global.Get("application_description") },
                        { "website", Global.Get("application_website") },
                        { "mainwindow", Global.Get("application_mainwindow") },
                        { "mainlanguage", Global.Get("application_mainlanguage") },
                        { "praebuild", Global.Get("application_präbuildevent") },
                        { "postbuild", Global.Get("application_postbuildevent") }
                    };

                PropsWriter.Save(Global.Get("propsPath"), dic);

                Application.isDirty = false;
            }
        }

        private void itemToolStripMenuItem_Click(object sender, EventArgs e)
        {
            var ni = new NewItem();
            if (ni.ShowDialog() == DialogResult.OK)
            {
                MessageBox.Show(ni.SelectedItemType);
            }
        }

        private void Form1_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (Application.isDirty)
            {
                if (MessageBox.Show("Would you close without saving changes?", "Close?", MessageBoxButtons.OKCancel)
                    == DialogResult.OK)
                {
                    Application.isDirty = false;
                    e.Cancel = false;
                }
                else
                {
                    e.Cancel = true;
                }
            }
            var s = new DockStateSerializer(
                this.dockContainer1, System.Windows.Forms.Application.StartupPath + "\\dock.xml");
            s.Save();
        }

        private void projectExplorerToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DockableFormInfo pe = this.dockContainer1.Add(
                this.explorer, zAllowedDock.Sides, Guid.Parse("F3CC9EFE-2B96-467A-9661-384345C1861C"));
            this.dockContainer1.DockForm(pe, DockStyle.Right, zDockMode.Inner);
        }

        private void errorsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DockableFormInfo error = this.dockContainer1.Add(
                Tools.Get<Form>("errorlist"), zAllowedDock.All, Guid.Parse("39E0431C-88F4-41BF-9EFA-9B71D8D50781"));
            this.dockContainer1.DockForm(error, DockStyle.Bottom, zDockMode.Outer);
        }

        private void editToolStripMenuItem_Click(object sender, EventArgs e)
        {
            DockableFormInfo edit = this.dockContainer1.Add(
                Tools.Get<Form>("editor"), zAllowedDock.All, Guid.Parse("9EFE2525-9BB3-487C-8955-A3E139CFE8B6"));
            this.dockContainer1.DockForm(edit, DockStyle.Fill, zDockMode.Inner);
        }

        private void Form1_Load(object s, EventArgs e)
        {
            Tools.Add("errorlist", new ErrorList());
            Tools.Add("editor", new Edit());

            this.explorer = new Explorer();

            this.dateiToolStripMenuItem.Text = Globalisation.Language["File"];
            this.neuToolStripMenuItem.Text = Globalisation.Language["New"];
            this.speichernToolStripMenuItem.Text = Globalisation.Language["Save"];
            this.öffnenToolStripMenuItem.Text = Globalisation.Language["Load"];
            this.projektToolStripMenuItem.Text = Globalisation.Language["Project"];
            this.projektToolStripMenuItem1.Text = Globalisation.Language["Project"];
            this.extensionsToolStripMenuItem.Text = Globalisation.Language["Extensions"];
            this.helpToolStripMenuItem.Text = Globalisation.Language["Help"];
            this.itemToolStripMenuItem.Text = Globalisation.Language["Item"];

            this.explorer.treeView1.NodeMouseDoubleClick += this.treeView1_NodeMouseDoubleClick;

            this.errorLister1 = (Tools.Get<Form>("errorlist") as ErrorList);
            this.tabControl1 = (Tools.Get<Form>("editor") as Edit);

            this._plugInManager = Program._plugInManager;

            foreach (var plugIn in this._plugInManager.PlugIns)
            {
                IApplicationPlugIn<IEditorPlugIn> @in = plugIn;
                this.extensionsToolStripMenuItem.DropDownItems.Add(
                    new ToolStripButton(@in.Name, null, (sender, args) => @in.PlugInProxy.OnSelect()));
                plugIn.PlugInProxy.Do();
            }

            Global.Add<ProjectFile>();

            Application.isDirtyChanged += (sender, args) =>
                {
                    if (Application.isDirty)
                    {
                        if (!this.Text.EndsWith("(*)"))
                        {
                            this.Text += "(*)";
                        }
                    }
                    else
                    {
                        if (this.Text.EndsWith("(*)"))
                        {
                            this.Text = this.Text.Remove(this.Text.Length - 3, 3);
                        }
                    }
                };
        }

        private void debugToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.erstellenToolStripMenuItem_Click(sender, e);
            Process.Start(Global.Get("buildPath") + Global.Get("application_name") + ".era");
        }
    }
} 